home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacHack 1994
/
MacHack 1994.toast
/
MacHack™ 1987-1994
/
MacHack™ '87
/
Xref.folder
/
xref.c
< prev
Wrap
C/C++ Source or Header
|
1987-01-08
|
17KB
|
578 lines
/********************************************************************/
/* Program: XRef.c */
/* This program comes from 'The C Programming Tutor' */
/* by Leon A. Wortman and Thomas O. Sidebottom. */
/* This program has typical UNIX interface and yields */
/* a numbered listing and an alphabetized cross */
/* reference listing with all reference line numbers */
/* of all C identifiers used in the program. */
/* */
/* Modified for the Alpha Micro C by John Pence */
/* compiles as a tool under MPW-Macintosh programers workshop also */
/********************************************************************/
/***********************************************************/
/* Include Files */
/***********************************************************/
#include <stdio.h>
#include <ctype.h>
/***********************************************************/
/* definitions */
/***********************************************************/
#define CR 13
#define BOOL int
#define DQUOTE '"'
#define EQUALS 0
#define FALSE 0
#define FIRSTGREATER 1
#define FIRSTLESS -1
#define HTSIZE 1009 /* Must be a prime number */
#define MAXSTRLEN 255
#define MAXWORDSIZE 20
#define SLASH '/'
#define SQUOTE '\''
#define STAR '*'
#define TRUE 1
#define VOID int
/***********************************************************/
/* code macros */
/***********************************************************/
#define PutBack(Ch) {PutBackChar = Ch; }
#define GenerateNewIndex( x, y ) ( ( (x + y * y) % HTSIZE))
/***********************************************************/
/* typedefs */
/***********************************************************/
typedef struct rType {
int Reference ; /* line number */
struct rType *Link; /* link to next reference */
}
RefType, *RefPtr ;
typedef struct tType {
char *Value ; /* pointer to token */
RefPtr OccurList ; /* line number list */
}
TokenType, *TokenPtr ;
/***********************************************************/
/* external functions */
/***********************************************************/
extern char *malloc() ;
extern RefPtr MakeOccurrence() ;
/***********************************************************/
/* global variables */
/***********************************************************/
int CurLineNo = 1 ; /* Line being read */
char OldChar, CurChar = '\0' ;
TokenType HashTable[HTSIZE] ;
int PutBackChar = '\0' ; /* Character put back after input */
/***********************************************************/
/* *** MAIN *** */
/***********************************************************/
main( argc, argv )
int argc;
char **argv ;
{ /* main */
int Counter ;
char CurToken [MAXSTRLEN] ;
FILE *InFile ;
/* There must be at least one command-line option.
*/
if ( argc < 2 ) {
fprintf(stderr, "USAGE: xref filename<cr>\n") ;
exit(0);
}
if (!(InFile = fopen(argv[1],"r"))) {
fprintf(stderr,"Can't open input file \"%s\".\n",argv[1]) ;
exit(0) ;
}
/* Initialize the Hash Table.
*/
for (Counter = 0; Counter < HTSIZE ; Counter++ ) {
HashTable[Counter].Value = NULL ;
HashTable[Counter].OccurList = NULL ;
}
/* Write the first line number to the output stream.
*/
printf("\n%4d ",CurLineNo) ;
/* Read and store each Token.
*/
while (GetNxtToken(CurToken,InFile)) {
if (InsertToken(CurToken)) {
fprintf(stderr,"Hash Table size exceeded.\n") ;
break ;
} /* if */
} /* while */
printf("*** END OF FILE ***\n\n") ;
/* Sort the Tokens alphabetically
*/
SortTokens(HTSIZE) ;
PrintTable() ;
} /* main */
/*==========================================================*/
/* *** AddOccurrence() *** */
/*==========================================================*/
VOID AddOccurrence(HeadPtr)
RefPtr HeadPtr ;
/* AddOccurrence adds a new line to the
* end of the list that HeadPtr begins.
*/
{ /* AddOccurrence */
RefPtr CurPtr ;
RefPtr NewPtr ;
/* Find the end of the list by starting at
* the begginning and advancing through the list
* until we find the end.
*/
for (CurPtr = HeadPtr; CurPtr->Link != NULL;
CurPtr = CurPtr->Link)
;
CurPtr->Link = NewPtr = (RefPtr)malloc(sizeof(RefType)) ;
if (NewPtr == NULL) {
fprintf(stderr,"Out of Memory in AddOccurrence.\0") ;
exit(0) ;
}
NewPtr->Reference = CurLineNo ;
NewPtr->Link = (RefPtr)NULL ;
} /* AddOccurrence */
/*==========================================================*/
/* *** Copy() *** */
/*==========================================================*/
char *Copy(OldString)
char *OldString ;
/* Copy makes a copy of OldString and returns the address of
* the copy.
*/
{ /* Copy */
char *NewString ;
/* Allocate a string able to hold the length
* of the string plus one for the terminator.
*/
NewString = malloc(strlen(OldString) +1) ;
/* Copy the string and return a pointer to it.
*/
strcpy(NewString,OldString) ;
return(NewString) ;
} /* Copy */
/*==========================================================*/
/* *** GetNxtChar() *** */
/*==========================================================*/
int GetNxtChar(InputFile)
FILE *InputFile ;
/* GetNxtChar returns the next non-comment
* a non-string character from InputFile.
*
* At least one character is read from InputFile. If
* the character could start a comment, the next character
* is checked. If the slash-star of a comment
* is read, the reading of characters continues until the end
* of the comment is found. If a single or double quote
* is read, the reading of characters continues until
* the closing mark is found. When EOF is encountered,
* EOF is returned. GetNxtChar therefore never returns
* characters inside comments or quotes.
*/
{ /* GetNxtChar */
int CheckChar ;
int NewChar ;
int TempChar ;
/* If end-of-file is found, return immediately.
*/
if ((NewChar = GetRawChar(InputFile)) == EOF)
return (EOF) ;
/* If a single or double quote is found, process the string.
*/
if (NewChar == SQUOTE || NewChar == DQUOTE) {
CheckChar = NewChar ;
/* Continue reading until the matching quote character
* is found.
*/
do {
if ((NewChar = GetRawChar(InputFile)) == '\\') {
/* If LITERAL QUOTE is found in string;
* ignore it.
*/
while (((NewChar = GetRawChar(InputFile)) != EOF) &&
(NewChar == DQUOTE)) ;
continue;
}
} while (NewChar != CheckChar && NewChar != EOF) ;
/* The terminating character has now been read.
* Read one more and return it.
*/
NewChar = GetRawChar(InputFile) ;
}
/* Next, handle comment processing. If SLASH is read,
* check to see if the next character is a STAR. If it is,
* continue reading until the next STAR-SLASH is found.
*/
else if (NewChar == SLASH) {
if ((TempChar = GetRawChar(InputFile)) != STAR) {
/* Not a comment; putback the character.
*/
PutBack(TempChar) ;
}
else
/* Here's a comment. Search for the end.
*/
do {
/* Read characters until a STAR is found.
*/
if (((NewChar = GetRawChar(InputFile)) == STAR) &&
NewChar != EOF) {
while (((NewChar = GetRawChar(InputFile)) == STAR) &&
NewChar != EOF) ;
if (NewChar == EOF)
break;
}
} while (NewChar != SLASH && NewChar != EOF) ; /* do */
NewChar = GetRawChar(InputFile) ;
} /* else if */
return (NewChar) ;
} /* GetNxtChar */
/*==========================================================*/
/* *** GetNxtToken() *** */
/*==========================================================*/
BOOL GetNxtToken(Buffer, InputFile)
char *Buffer ;
FILE *InputFile ;
/* GetNxtToken returns in Buffer, the next valid C token in the
* program.
*/
{ /* GetNxtToken */
int CurChar, OldChar ;
/* Read the characters from the InputFile until starting letter is
* found. Stop when a valid letter or end-of-file is found.
*/
while (!IsStartingLetter(CurChar = GetNxtChar(InputFile), OldChar) &&
CurChar != EOF)
OldChar = CurChar;
/* Read the first character.
*/
*Buffer++ = CurChar ;
/* Read and accumulate characters in buffer while they are
* valid letters for a token.
*/
while (IsTokenLetter(CurChar = GetNxtChar(InputFile)) &&
CurChar != EOF)
*Buffer++ = CurChar ;
/* Put back the last character we read.
*/
if (CurChar != EOF)
PutBack(CurChar) ;
/* Terminate the Token.
*/
*Buffer = '\0' ;
/* Return end-of-file status.
*/
return ((CurChar == EOF) ? FALSE : TRUE) ;
} /* GetNxtToken */
/*==========================================================*/
/* *** GetRawChar() *** */
/*==========================================================*/
int GetRawChar(InputFile)
FILE *InputFile ;
/* GetRawChar reads the next character fromn the InputFile and
* returns it. If a newline is read, it increments
* CurLineNo. If end-of-file is read, it returns EOF.
*/
{ /* GetRawChar */
int NextChar ;
/* Check PutBackChar to see if the next character has
* already been read. If so, process it and set PutBackChar
* to the NULL character.
*/
if (PutBackChar != '\0') {
NextChar = PutBackChar ;
PutBackChar = '\0' ;
}
else {
/* Echo the character read to the output stream.
* If a CR is read, increment the line count.
*/
if ((NextChar = getc(InputFile)) == '\n')
printf("\n%4d ", ++CurLineNo) ;
else {
if (NextChar != EOF)
putchar(NextChar) ;
}
}
if (NextChar == EOF)
return (EOF) ;
return (NextChar) ;
} /* GetRawChar */
/*==========================================================*/
/* *** Hash() *** */
/*==========================================================*/
int Hash(Word)
char *Word ;
/* Hash returns the HTIndex of the Word passed, or an
* appropriate HTIndex for the Word. If HashTable is
* full, Hash returns -1.
*/
{ /* Hash */
int HTIndex ;
int IdLen ;
int InitHTIndex ;
int ProbeCounter = 0 ;
IdLen = strlen(Word) ;
if (IdLen == 0)
printf("Hash: Word of no length\n") ;
HTIndex = InitHTIndex = TransformId(Word) ;
if (HashTable[HTIndex].Value == NULL)
; /* no-op - We've got it. */
else /* Have we found the correct index? */
if (strcmp(Word,HashTable[HTIndex].Value) == EQUALS)
; /* DONE: A direct hit! */
else /* Collision -- generate indexes */
for (ProbeCounter=0; ProbeCounter<(HTSIZE / 2);
ProbeCounter++) {
HTIndex = GenerateNewIndex(InitHTIndex, ProbeCounter) ;
if (HashTable[HTIndex].Value == NULL)
break ; /* We've got it ! */
else if (strcmp(Word,HashTable[HTIndex].Value)
== EQUALS)
break ; /* We've got it ! */
}
if (ProbeCounter >= (HTSIZE / 2))
return(-1) ;
return(HTIndex) ;
} /* Hash */
/*==========================================================*/
/* *** InsertToken() *** */
/*==========================================================*/
BOOL InsertToken(Token)
char *Token ;
/* Inserts the Token into the hash table if it is new. If
* the Token is previously known, it adds the line number
* to the occurrence list. It then returns FALSE.
* If the end-of-hash table is reached, TRUE is returned.
*/
{ /* InsertToken */
int HTIndex ;
HTIndex = Hash(Token) ;
if (HTIndex == -1)
return(TRUE) ;
if (HashTable[HTIndex].Value == NULL) {
HashTable[HTIndex].Value = Copy(Token) ;
HashTable[HTIndex].OccurList = MakeOccurrence() ;
}
else
AddOccurrence(HashTable[HTIndex].OccurList) ;
return(FALSE) ;
} /* InsertToken */
/*==========================================================*/
/* *** IsStartingLetter() *** */
/*==========================================================*/
BOOL IsStartingLetter(Ch, Ch2)
char Ch, Ch2 ;
/* IsStartingLetter returns TRUE if Ch is a valid character to
* begin a C token.
*/
{ /* IsStartingLetter */
return (((isalpha(Ch) || Ch == '_') &&
(!isdigit(Ch2))) ? TRUE : FALSE) ;
} /* IsStartingLetter */
/*==========================================================*/
/* *** IsTokenLetter() *** */
/*==========================================================*/
BOOL IsTokenLetter(Ch)
char Ch ;
/* IsTokenLetter returns TRUE if Ch is a valid character
* inside a C token.
*/
{ /* IsTokenLetter */
return ((isalpha(Ch) || isdigit(Ch) || Ch == '_') ? TRUE : FALSE) ;
} /* IsTokenLetter */
/*==========================================================*/
/* *** MakeOccurrence() *** */
/*==========================================================*/
RefPtr MakeOccurrence()
/* MakeOccurrence creates the first entry of the line occurrence
* list. It creates the next node in the list, inserts CurLineNo
* and sets Link to NULL in preparation for the next entry.
*/
{ /* MakeOccurrence */
RefPtr NewNode ;
if ((NewNode = (RefPtr)malloc(sizeof(RefType))) == NULL) {
fprintf(stderr,"Out of Memory in MakeOccurrence.\n") ;
exit(0) ;
}
NewNode->Reference = CurLineNo ;
NewNode->Link = (RefPtr)NULL ;
return (NewNode) ;
} /* MakeOccurrence */
/*==========================================================*/
/* *** NameCompare() *** */
/*==========================================================*/
int NameCompare(First,Second)
int First ;
int Second ;
/* NameCompare compares two entries in HashTable referenced
* by the indices First and Second. It returns FIRSTLESS if
* First < Second; EQUALS if they are equal;
* and FIRSTGREATER if First > Second.
*/
{ /* NameCompare */
/* If the first entry has no value, the first is less.
*/
if (HashTable[First].Value == NULL)
return (FIRSTLESS) ;
/* Then if the second has no value, the first is greater.
*/
if (HashTable[Second].Value == NULL)
return (FIRSTGREATER) ;
/* Otherwise return the comparison from strcmp.
*/
return (strcmp(HashTable[First].Value, HashTable[Second].Value)) ;
} /* NameCompare */
/*==========================================================*/
/* *** PrintTable() *** */
/*==========================================================*/
VOID PrintTable()
/* PrintTable prints the list of identifiers and line occurrences.
*/
{ /* PrintTable */
RefPtr ListPtr ;
int NumOnLine ;
int TokenCounter ;
for (TokenCounter = 0 ; TokenCounter < HTSIZE ;
TokenCounter++) {
if (HashTable[TokenCounter].Value) {
printf("\n%-20s ",HashTable[TokenCounter].Value) ;
for (ListPtr = HashTable[TokenCounter].OccurList, NumOnLine = 0;
ListPtr != NULL;
ListPtr = ListPtr->Link, NumOnLine++ ) {
if (NumOnLine == 10) {
printf("\n ") ;
NumOnLine = 0 ;
}
printf("%3d ", ListPtr->Reference) ;
}
}
}
printf("\n") ;
} /* PrintTable */
/*==========================================================*/
/* *** SortTokens() *** */
/*==========================================================*/
VOID SortTokens(SortNumber)
int SortNumber ;
/* SortTokens sorts the tokens into alphabetical order
* using a shell sort.
*/
{ /* SortTokens */
TokenType Exchange ;
int BaseCounter ;
int CurCounter ;
int CurGapCounter ;
int Gap ;
int LastInBuf ;
LastInBuf = SortNumber ;
/* Look through all Gaps starting with a gap half the
* size of the list. Each time reduce the size of the gap
* by dividing by two.
*/
for (Gap = LastInBuf / 2; Gap > 0; Gap /= 2)
/* BaseCounter moves between the Gap-th element and
* the last element in the list. The sort using the
* current Gap runs until 1 is the LastInBuf-th
* element in the list.
*/
for (BaseCounter = Gap; BaseCounter < LastInBuf; BaseCounter++)
/* For a BaseCounter, we compare the CurCounter-th and
* the CurGapCounter-th elements in the list. CurCounter
* and CurGapCounter are always separated by Gap.
*/
for (CurCounter = BaseCounter - Gap; CurCounter >= 0; CurCounter -= Gap) {
CurGapCounter = CurCounter + Gap ;
/* If the two elements compare correctly, stop.
*/
if (NameCompare(CurCounter, CurGapCounter) < EQUALS)
break;
/* Otherwise, exchange the elements.
*/
Exchange.Value = HashTable[CurCounter].Value ;
Exchange.OccurList = HashTable[CurCounter].OccurList ;
HashTable[CurCounter].Value = HashTable[CurGapCounter].Value ;
HashTable[CurCounter].OccurList = HashTable[CurGapCounter].OccurList ;
HashTable[CurGapCounter].Value = Exchange.Value ;
HashTable[CurGapCounter].OccurList = Exchange.OccurList ;
}
} /* SortTokens */
/*==========================================================*/
/* *** TransformID() *** */
/*==========================================================*/
int TransformId(Word)
char Word[] ;
/* Converts an identifier into an integer within the index
* range of HashTable. A polynomial is generated and reduced
* modulo HTSIZE to produce this number.
*/
{ /* TransformId */
int Term = 0 ;
int WordIndex ;
for (WordIndex = strlen(Word)-1 ; (WordIndex >= 0) ; WordIndex--)
Term = (257*Term) + Word[ WordIndex ] ;
Term = (Term < 0 ) ? -Term : Term ;
return(Term % HTSIZE) ;
} /* TransformId */